package com.wang.jmonkey.common.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.wang.jmonkey.common.model.dto.BaseTreeDto;
import org.apache.commons.lang3.ObjectUtils;

import java.util.*;

/**
 * @Description 树形结构构造器
 * @Author HeJiawang
 * @Date 2021/5/22 10:57
 */
public final class TreeUtil {

    /**
     * 构造树形结构数据<br/>
     * 不用指定最上级节点，当某个节点没有父级节点时，程序判断为顶级节点
     * @param sourceNodeList list数据
     * @param <T> 继承自BaseTreeDto
     * @return 树形结构数据
     */
    public static <T extends BaseTreeDto> List<T> build(List<T> sourceNodeList) {
        if (CollUtil.isEmpty(sourceNodeList)) return sourceNodeList;

        List<T> nodeList = ObjectUtil.cloneByStream(sourceNodeList); // 将list中的数据深复制，避免原始list结构变化
        Map<Long, List<T>> parentMap = new HashMap<>();
        Map<Long, T> map = new HashMap<>();
        List<T> roots = new ArrayList<>();

        nodeList.forEach(node -> {
            boolean isRoot = true;   // 判断是否为根节点
            for (T n : nodeList) {
                if (node.getParentId() == n.getId()) { // 不是根节点
                    isRoot = false;
                    break;
                }
            }

            if (isRoot) {
                roots.add(node);
            } else {
                if (parentMap.containsKey(node.getParentId())) {
                    parentMap.get(node.getParentId()).add(node);
                } else {
                    List<T> childOrgList = CollUtil.newArrayList(node);
                    parentMap.put(node.getParentId() , childOrgList);
                }
            }

            map.put(node.getId() , node);
        });

        parentMap.entrySet().forEach(entry -> {
            if (map.containsKey(entry.getKey())) {
                map.get(entry.getKey()).addAllChildren(entry.getValue());
            }
        });

        return roots;

    }

    /**
     * 构造树形结构数据 <br/>
     * 入参的nodeList结构不会改变
     * @param sourceNodeList list数据
     * @param root 根节点信息
     * @param <T> 继承自BaseTreeDto
     * @return 树形结构数据
     */
    public static <T extends BaseTreeDto> List<T> build(List<T> sourceNodeList, Long root) {
        if (CollUtil.isEmpty(sourceNodeList)) return sourceNodeList;

        List<T> nodeList = ObjectUtil.cloneByStream(sourceNodeList); // 将list中的数据深复制，避免原始list结构变化

        List<T> treeList = CollUtil.newArrayList();
        nodeList.forEach(node -> {
            if (ObjectUtil.isNotEmpty(root) && ObjectUtil.isNotEmpty(node.getParentId())
                    && root.compareTo(node.getParentId()) == 0) {
                treeList.add(node);
            }

            nodeList.forEach(nodeChildren -> {
                if (nodeChildren.getParentId() == node.getId()) {
                    node.addChildren(nodeChildren);
                }
            });
        });

        return treeList;
    }
}
